/*
 heat-spectral lib. solves time-dependent PDEs using SEM-NI method.
 Copyright (C) 2009, Altieri Michele and Stefanoni Andrea
 Copyright (C) 2008, Proverbio Alessandro and Radice David

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/**
    \file point.hpp
    \brief Point class

    This simple class is just an implementation of
    a point in a bidimensional manifold.
*/

# ifndef POINT_HPP
# define POINT_HPP 1

# include<cassert>
# include<iostream>

namespace spectral {

/**
    \class Point
    \brief Point class

    This simple class is just an implementation of
    a point in a bidimensional manifold.
*/

/**
    \fn Point::Point()
    \brief Trivial constructor

*/

/**
    \fn Point::Point(T const a, T const b)
    \brief Point constructor

    This will build a point given its coordinates
*/

/**
    \fn Point::Point(Point<T> const & P)
    \brief Point copy constructor

    This is used to let a Point to be initializated
    as equal to another Point
*/

/**
    \fn T & Point::operator[](int n)
    \brief Point coordinate

    Returns a reference to the \e n-sim coordinate of the point.
    If P is a Point than P[n] can be a left member.
*/

/**
    \fn T Point::operator[](int n) const
    \brief Point coordinate

    Returns the \e n-sim coordinate of the point.
*/

/**
    \fn Point<T> & Point::operator=(Point<T> const & P)
    \brief Overloaded operator =

*/

/**
    \fn void Point::move(Point<T> const & P)
    \brief Moves the point to a new position

*/

/**
    \fn void Point::move(T a, T b)
    \brief Moves the point to a new position

*/

/**
    \fn void Point::ptplus(T a)
    \brief Adds a to the coordinates of the point

*/

/**
    \fn T Point::get(int n) const
    \brief Point coordinate

    Returns the \e n-sim coordinate of the point.
*/

/**
    \fn std::ostream & operator<<(std::ostream & strm,Point<T> const & P)
    \brief The '<<' operator for the points

    This is used to print points in an human readable manner
*/

/**
    \fn std::istream & operator>>(std::istream & strm,Point<T> & P)
    \brief The '>>' operator for the points

    It just do:
    \code strm >> P[0] >> P[1]; return strm; \endcode
    so the x-coordinate is the first written, while the y-one
    is the second.
*/

template<class T>
class Point {
    public:
        Point() {};
        Point(T const a, T const b);
        Point(Point<T> const & P);
        T & operator[](int n);
        T operator[](int n) const;
        Point<T> & operator=(Point<T> const & P);
        void move(Point<T> const & P);
        void move(T a, T b);
        void ptplus( T a );
        T get(int n) const;
    private:
        T _values[2];    /**< \brief Coordinates of the point */
};

template<class T>
std::ostream & operator<<(std::ostream & strm,Point<T> const & P);

template<class T>
std::istream & operator>>(std::istream & strm,Point<T> & P);

// =======================================================
// Template Implementations
// =======================================================

template<class T>
Point<T>::Point(T const a, T const b) {
    _values[0]=a;
    _values[1]=b;
}

template<class T>
Point<T>::Point(Point<T> const & P) {
    _values[0]=P._values[0];
    _values[1]=P._values[1];
}

template<class T>
T & Point<T>::operator[](int n) {
    assert( n>=0 && n<2 );
    return _values[n];
}

template<class T>
T Point<T>::operator[](int n) const {
    assert( n>=0 && n<2 );
    return _values[n];
}

template<class T>
Point<T> & Point<T>::operator=(Point<T> const & P) {
    _values[0]=P._values[0];
    _values[1]=P._values[1];
    return *this;
}

template<class T>
void Point<T>::move(Point<T> const & P) {
    _values[0]=P._values[0];
    _values[1]=P._values[1];
}

template<class T>
void Point<T>::move(T a, T b) {
    _values[0]=a;
    _values[1]=b;
}

template<class T>
void Point<T>::ptplus( T a )
{
    _values[0] = _values[0]+a;
    _values[1] = _values[1]+a;
}

template<class T>
T Point<T>::get(int n) const {
    assert( n>=0 && n<2 );
    return _values[n];
}

template<class T>
std::ostream & operator<<(std::ostream & strm,Point<T> const & P) {
    strm << "(" << P.get(0) << "," << P.get(1) << ")";
    return strm;
}

template<class T>
std::istream & operator>>(std::istream & strm,Point<T> & P) {
    strm >> P[0] >> P[1];
    return strm;
}


} //namespace

# endif
